if (!Function.prototype.bind) {
  Function.prototype.bind = function (oThis) {
    if (typeof this !== "function") {
      // closest thing possible to the ECMAScript 5 internal IsCallable function
      throw new TypeError("Function.prototype.bind - what is trying to be bound is not callable");
    }

    var aArgs = Array.prototype.slice.call(arguments, 1), 
        fToBind = this, 
        fNOP = function () {},
        fBound = function () {
          return fToBind.apply(this instanceof fNOP && oThis
                                 ? this
                                 : oThis || window,
                               aArgs.concat(Array.prototype.slice.call(arguments)));
        };

    fNOP.prototype = this.prototype;
    fBound.prototype = new fNOP();

    return fBound;
  };
}

/**
1、思路

（1）因为bind方法不会立即执行函数，需要返回一个待执行的函数（这里用到闭包，可以返回一个函数）
return function(){}

（2）作用域绑定，这里可以使用apply或者call方法来实现 xx.call(yy)/xx.apply(yy)

（3）参数传递，由于参数的不确定性，需要用apply传递数组（实例更明了）xx.apply(yy,[...Array...])，
如果用call就不太方便了，因为call后面的参数需要一个个列出来。
 */
Function.prototype.bind = function(newThis) {
    var aArgs = Array.prototype.slice.call(arguments, 1) //拿到除了newThis之外的预置参数序列
    var that = this
    return function() {
        return that.apply(newThis, aArgs.concat(Array.prototype.slice.call(arguments)))
        //绑定this同时将调用时传递的序列和预置序列进行合并
    }
}